package com.xmmj.baselibrary.base.activity.statusbar

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.*
import android.widget.FrameLayout
import com.xmmj.baselibrary.R
import com.xmmj.baselibrary.base.activity.permission.PermissionActivity
import java.lang.reflect.Method
import kotlin.math.min

/**
 * 支持设置系统状态栏的Activity
 */
@SuppressLint("PrivateApi")
open class StatusBarActivity : PermissionActivity() {
    //系统配置
    private var config: SystemBarConfig? = null

    //状态栏是否可用
    private var statusBarAvailable = true

    //导航栏是否可用
    private var navBarAvailable = false

    //状态栏
    private var statusBarView: View? = null

    //导航栏
    private var navBarView: View? = null

    //是否启用系统导航栏
    private var navBarEnabled = false

    //是否启用系统状态栏
    private var statusBarEnabled = true

    //通过反射获知当前系统是否存在导航栏
    init {
        if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
            try {
                val c = Class.forName("android.os.SystemProperties")
                val m: Method = c.getDeclaredMethod("get", String::class.java)
                m.isAccessible = true
                navBarOverride = m.invoke(null, "qemu.hw.mainkeys") as String?
            } catch (e: Throwable) {
                navBarOverride = null
            }
        }
    }

    companion object {
        //默认的系统栏颜色值.
        const val DEFAULT_COLOR = -0x67000000

        //判断导航栏是否存在，1：不存在，0：存在
        private var navBarOverride: String? = null

        private const val SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT = 0x00000010

        /**
         * 设置OPPO状态栏是否为高亮模式
         *
         * @param activity 上下文
         * @param light    高亮
         */
        private fun setOPPOStatusTextColor(activity: Activity, light: Boolean) {
            val window = activity.window
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            var vis = window.decorView.systemUiVisibility
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                vis = if (light) {
                    vis or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
                } else {
                    vis and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
                }
            } else if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
                vis = if (light) {
                    vis or SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT
                } else {
                    vis and SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT.inv()
                }
            }
            window.decorView.systemUiVisibility = vis
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val win = window
        val decorViewGroup = win.decorView as ViewGroup
        if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
            //检查样式属性
            val attrs = intArrayOf(
                android.R.attr.windowTranslucentStatus,
                android.R.attr.windowTranslucentNavigation
            )
            val a = obtainStyledAttributes(attrs)
            try {
                statusBarAvailable = a.getBoolean(0, false)
                navBarAvailable = a.getBoolean(0, false)
            } finally {
                a.recycle()
            }

            //检查状态栏是否可用
            val winParams = win.attributes
            var bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
            if (winParams.flags and bits != 0) {
                statusBarAvailable = true
            }
            //检查导航栏是否可用
            bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
            if (winParams.flags and bits != 0) {
                navBarAvailable = true
            }
        }
        config = SystemBarConfig(this, statusBarAvailable, navBarAvailable)

        //设置透明状态栏
        setTranslucentStatus()

        //检查设备是否存在导航栏
        if (!config!!.hasNavigationBar()) {
            navBarAvailable = false
        }

        //设置状态栏
        if (statusBarAvailable) {
            setupStatusBarView(decorViewGroup)
        }

        //设置导航栏
        if (navBarAvailable) {
            setupNavBarView(decorViewGroup)
        }

        //设置状态栏背景
        setStatusBarResource(setStatusBarResource())

        //设置状态栏高亮模式
        setStatusBarLightMode(this, isStatusBarLightMode())
    }

    /**
     * 是否启用系统状态栏
     */
    open fun isStatusBarEnabled(): Boolean {
        return statusBarEnabled
    }

    /**
     * 是否启用系统导航栏
     */
    open fun isNavBarEnabled(): Boolean {
        return navBarEnabled
    }

    /**
     * 状态栏高亮模式(字体和图标为黑色，背景为透明)
     */
    open fun isStatusBarLightMode(): Boolean {
        return true
    }

    /**
     * 设置状态栏颜色
     */
    open fun setStatusBarResource(): Int {
        return R.color.color_transparent
    }

    /**
     * 获得状态栏的高度
     */
    open val statusBarHeight: Int
        get() {
            val resources = resources
            val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
            return resources.getDimensionPixelSize(resourceId)
        }

    /**
     * 代码实现android:fitsSystemWindows
     *
     * @param activity 上下文
     */
    private fun setRootViewFitsSystemWindows(activity: Activity, fitSystemWindows: Boolean) {
        if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
            val winContent = activity.findViewById<ViewGroup>(android.R.id.content)
            if (winContent.childCount > 0) {
                val rootView = winContent.getChildAt(0) as ViewGroup
                rootView.fitsSystemWindows = fitSystemWindows
            }
        }
    }

    /**
     * 修改状态栏颜色，支持4.4以上版本
     *
     * @param colorId 颜色
     */
    private fun setStatusBarColor2(colorId: Int) {
        if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
            val window = window
            window.statusBarColor = resources.getColor(colorId)
        } else if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
            //状态栏设置为透明
            setTranslucentStatus()
            //显示状态栏
            statusBarEnabled = true
            //设置状态栏颜色
            setStatusBarColor(colorId)
        }
    }

    /**
     * 设置透明状态栏
     */
    private fun setTranslucentStatus() {
        val window = window
        if (Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT) {
            //5.x开始需要把颜色设置透明，否则导航栏会呈现系统默认的浅灰色
            val decorView = window.decorView
            //两个flag要结合使用，表示让应用的主体内容占用系统状态栏的空间
            val option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            decorView.systemUiVisibility = option
            //window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.statusBarColor = Color.TRANSPARENT
            //导航栏颜色也可以正常设置
            //window.setNavigationBarColor(Color.TRANSPARENT);
        } else {
            val attributes = window.attributes
            val flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
            attributes.flags = attributes.flags or flagTranslucentStatus
            ///int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
            ///attributes.flags |= flagTranslucentNavigation;
            window.attributes = attributes
        }
    }

    /**
     * 设置是否启用系统导航栏
     *
     * 如果平台没有软导航键，正在运行Jelly Bean或更早，或者在主题或窗口标志中都没有启用半透明的系统UI模式，则此方法不执行任何操作。
     *
     * @param enabled 启用
     */
    private fun setNavigationBarEnabled(enabled: Boolean) {
        navBarEnabled = enabled
        if (navBarAvailable) {
            navBarView!!.visibility = if (enabled) View.VISIBLE else View.GONE
        }
    }

    /**
     * 设置状态栏颜色
     *
     * @param color 颜色
     */
    private fun setStatusBarColor(color: Int) {
        if (statusBarAvailable) {
            statusBarView!!.setBackgroundColor(resources.getColor(color))
        }
    }

    /**
     * 设置状态栏的背景
     *
     * @param res 资源
     */
    private fun setStatusBarResource(res: Int) {
        if (statusBarAvailable) {
            statusBarView!!.setBackgroundResource(res)
        }
    }

    /**
     * 设置状态栏的绘制资源
     *
     * @param drawable 图像
     */
    private fun setStatusBarDrawable(drawable: Drawable) {
        if (statusBarAvailable) {
            statusBarView!!.setBackgroundDrawable(drawable)
        }
    }

    /**
     * 设置状态栏的透明度
     *
     * @param alpha 透明度
     */
    private fun setStatusBarAlpha(alpha: Float) {
        if (statusBarAvailable && Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
            statusBarView!!.alpha = alpha
        }
    }

    /**
     * 设置导航栏的背景色
     *
     * @param color 颜色
     */
    private fun setNavigationBarColor(color: Int) {
        if (navBarAvailable) {
            navBarView!!.setBackgroundColor(color)
        }
    }

    /**
     * 设置导航栏的背景
     *
     * @param res 资源
     */
    private fun setNavigationBarResource(res: Int) {
        if (navBarAvailable) {
            navBarView!!.setBackgroundResource(res)
        }
    }

    /**
     * 设置导航栏背景
     *
     * @param drawable 图像
     */
    private fun setNavigationBarDrawable(drawable: Drawable) {
        if (navBarAvailable) {
            navBarView!!.setBackgroundDrawable(drawable)
        }
    }

    /**
     * 设置导航栏的透明度
     *
     * @param alpha 透明度
     */
    private fun setNavigationBarAlpha(alpha: Float) {
        if (navBarAvailable && Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) {
            navBarView!!.alpha = alpha
        }
    }

    /**
     * 设置状态栏视图
     *
     * @param decorViewGroup 根布局
     */
    private fun setupStatusBarView(decorViewGroup: ViewGroup) {
        statusBarView = View(this)
        val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 200)
        params.gravity = Gravity.TOP
        if (navBarAvailable && !config!!.isNavigationAtBottom) {
            params.rightMargin = config!!.navigationBarWidth
        }
        statusBarView!!.layoutParams = params
        statusBarView!!.setBackgroundColor(DEFAULT_COLOR)
        statusBarView!!.visibility = View.GONE
        decorViewGroup.addView(statusBarView)
    }

    /**
     * 设置状态栏是否为高亮模式
     * （高亮模式指：黑色字体和图标，透明背景。适配4.4以上版本MIUI、Flyme和6.0以上版本其他Android）
     *
     * @param activity 上下文
     * @param light    高亮
     */
    private fun setStatusBarLightMode(activity: Activity, light: Boolean): Int {
        var result = 0
        if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
            if (miuiSetStatusBarLightMode(activity, light)) { //小米
                result = 1
            } else if (flymeSetStatusBarLightMode(activity.window, light)) { //魅族
                result = 2
            } else if (Build.MANUFACTURER.equals("OPPO", ignoreCase = true)) { //OPPO
                setOPPOStatusTextColor(activity, light)
                result = 3
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //Android6.0以上系统
                if (light) {
                    activity.window.decorView.systemUiVisibility =
                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
                } else {
                    activity.window.decorView.systemUiVisibility =
                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_VISIBLE
                }
                result = 4
            }
        }
        return result
    }

    /**
     * 设置魅族状态栏文字是否为高亮模式
     *
     * @param window 需要设置的窗口
     * @param light  高亮模式
     */
    private fun flymeSetStatusBarLightMode(window: Window?, light: Boolean): Boolean {
        var result = false
        if (window != null) {
            try {
                val lp = window.attributes
                val darkFlag = WindowManager.LayoutParams::class.java
                    .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON")
                val meizuFlags = WindowManager.LayoutParams::class.java
                    .getDeclaredField("meizuFlags")
                darkFlag.isAccessible = true
                meizuFlags.isAccessible = true
                val bit = darkFlag.getInt(null)
                var value = meizuFlags.getInt(lp)
                value = if (light) {
                    value or bit
                } else {
                    value and bit.inv()
                }
                meizuFlags.setInt(lp, value)
                window.attributes = lp
                result = true
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return result
    }

    /**
     * 设置小米状态栏字体是否为高亮模式（需要MIUI 6以上）
     *
     * @param activity 上下文
     * @param light    高亮
     */
    @SuppressLint("PrivateApi")
    private fun miuiSetStatusBarLightMode(activity: Activity, light: Boolean): Boolean {
        var result = false
        val window = activity.window
        if (window != null) {
            val clazz: Class<out Window> = window.javaClass
            try {
                val layoutParams = Class.forName("android.view.MiuiWindowManager\$LayoutParams")
                val field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
                val darkModeFlag = field.getInt(layoutParams)
                val extraFlagField = clazz.getMethod(
                    "setExtraFlags",
                    Int::class.javaPrimitiveType,
                    Int::class.javaPrimitiveType
                )
                if (light) {
                    //状态栏透明且黑色字体
                    extraFlagField.invoke(window, darkModeFlag, darkModeFlag)
                } else {
                    //清除黑色字体
                    extraFlagField.invoke(window, 0, darkModeFlag)
                }
                result = true
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    //开发版 7.7.13 及以后版本采用了系统API，旧方法无效但不会报错，所以两个方式都要加上
                    if (light) {
                        activity.window.decorView.systemUiVisibility =
                            (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                    or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
                    } else {
                        activity.window.decorView.systemUiVisibility =
                            (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                    or View.SYSTEM_UI_FLAG_VISIBLE)
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return result
    }

    /**
     * 设置导航栏视图
     *
     * @param decorViewGroup 根布局
     */
    private fun setupNavBarView(decorViewGroup: ViewGroup) {
        navBarView = View(this)
        val params: FrameLayout.LayoutParams
        if (config!!.isNavigationAtBottom) {
            params = FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                config!!.navigationBarHeight
            )
            params.gravity = Gravity.BOTTOM
        } else {
            params = FrameLayout.LayoutParams(
                config!!.navigationBarWidth,
                FrameLayout.LayoutParams.MATCH_PARENT
            )
            params.gravity = Gravity.RIGHT
        }
        navBarView!!.layoutParams = params
        navBarView!!.setBackgroundColor(DEFAULT_COLOR)
        navBarView!!.visibility = View.GONE
        decorViewGroup.addView(navBarView)
    }

    /**
     * 系统配置
     */
    private class SystemBarConfig(
        activity: Activity,
        translucentStatusBar: Boolean,
        translucentNavBar: Boolean
    ) {
        /**
         * 获取系统状态栏高度
         */
        val statusBarHeight: Int

        /**
         * 获取ActionBar的高度
         */
        val actionBarHeight: Int
        private val mHasNavigationBar: Boolean

        /**
         * 获取系统导航栏的高度
         */
        val navigationBarHeight: Int

        /**
         * 获取系统导航栏在屏幕上的宽度
         */
        val navigationBarWidth: Int

        private val mTranslucentStatusBar: Boolean

        private val mTranslucentNavBar: Boolean

        private val mInPortrait: Boolean

        private val mSmallestWidthDp: Float

        companion object {
            private const val STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"
            private const val NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"
            private const val NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"
            private const val NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"
            private const val SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"
        }

        init {
            val res = activity.resources
            mInPortrait = res.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
            mSmallestWidthDp = getSmallestWidthDp(activity)
            statusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME)
            actionBarHeight = getActionBarHeight(activity)
            navigationBarHeight = getNavigationBarHeight(activity)
            navigationBarWidth = getNavigationBarWidth(activity)
            mHasNavigationBar = navigationBarHeight > 0
            mTranslucentStatusBar = translucentStatusBar
            mTranslucentNavBar = translucentNavBar
        }

        private fun getActionBarHeight(context: Context): Int {
            var result = 0
            if (Build.VERSION_CODES.ICE_CREAM_SANDWICH <= Build.VERSION.SDK_INT) {
                val tv = TypedValue()
                context.theme.resolveAttribute(android.R.attr.actionBarSize, tv, true)
                result = TypedValue.complexToDimensionPixelSize(
                    tv.data,
                    context.resources.displayMetrics
                )
            }
            return result
        }

        private fun getNavigationBarHeight(context: Context): Int {
            val res = context.resources
            val result = 0
            if (Build.VERSION_CODES.ICE_CREAM_SANDWICH <= Build.VERSION.SDK_INT) {
                if (hasNavBar(context)) {
                    val key: String = if (mInPortrait) {
                        NAV_BAR_HEIGHT_RES_NAME
                    } else {
                        NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME
                    }
                    return getInternalDimensionSize(res, key)
                }
            }
            return result
        }

        private fun getNavigationBarWidth(context: Context): Int {
            val res = context.resources
            val result = 0
            if (Build.VERSION_CODES.ICE_CREAM_SANDWICH <= Build.VERSION.SDK_INT) {
                if (hasNavBar(context)) {
                    return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME)
                }
            }
            return result
        }

        private fun hasNavBar(context: Context): Boolean {
            val res = context.resources
            val resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android")
            return if (resourceId != 0) {
                var hasNav = res.getBoolean(resourceId)
                // check override flag (see static block)
                if ("1" == navBarOverride) {
                    hasNav = false
                } else if ("0" == navBarOverride) {
                    hasNav = true
                }
                hasNav
            } else { // fallback
                !ViewConfiguration.get(context).hasPermanentMenuKey()
            }
        }

        private fun getInternalDimensionSize(res: Resources, key: String): Int {
            var result = 0
            val resourceId = res.getIdentifier(key, "dimen", "android")
            if (resourceId > 0) {
                result = res.getDimensionPixelSize(resourceId)
            }
            return result
        }

        private fun getSmallestWidthDp(activity: Activity): Float {
            val metrics = DisplayMetrics()
            if (Build.VERSION_CODES.JELLY_BEAN <= Build.VERSION.SDK_INT) {
                activity.windowManager.defaultDisplay.getRealMetrics(metrics)
            } else {
                activity.windowManager.defaultDisplay.getMetrics(metrics)
            }
            val widthDp = metrics.widthPixels / metrics.density
            val heightDp = metrics.heightPixels / metrics.density
            return min(widthDp, heightDp)
        }

        /**
         * 判断系统导航栏是否在屏幕底部
         */
        val isNavigationAtBottom: Boolean
            get() = mSmallestWidthDp >= 600 || mInPortrait

        /**
         * 该设备是否存在系统导航栏
         */
        fun hasNavigationBar(): Boolean {
            return mHasNavigationBar
        }
    }
}